<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue 3 响应式基础教程 - 冒险者训练营</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <style>
    body {
      font-family: 'Arial', sans-serif;
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
      background-color: #f5f5f5;
    }
    .section {
      background: white;
      border-radius: 8px;
      padding: 20px;
      margin-bottom: 20px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
    .title {
      color: #42b983;
      border-bottom: 2px solid #42b983;
      padding-bottom: 10px;
    }
    .code {
      background: #f0f0f0;
      padding: 10px;
      border-radius: 4px;
      overflow-x: auto;
    }
    button {
      background: #42b983;
      color: white;
      border: none;
      padding: 8px 16px;
      border-radius: 4px;
      cursor: pointer;
      margin: 5px;
    }
    button:hover {
      background: #3aa876;
    }
    button:disabled {
      background: #ccc;
      cursor: not-allowed;
    }
    .hero-card {
      border: 2px solid #333;
      border-radius: 8px;
      padding: 15px;
      margin: 10px 0;
      background: #fff9e6;
    }
    .game-log {
      height: 100px;
      overflow-y: auto;
      background: #f0f0f0;
      padding: 10px;
      margin: 10px 0;
      border-radius: 4px;
    }
    .level-up {
      animation: glow 1s infinite alternate;
    }
    @keyframes glow {
      from { box-shadow: 0 0 5px #42b983; }
      to { box-shadow: 0 0 20px #42b983; }
    }
    .highlight {
      color: #e74c3c;
      font-weight: bold;
    }
  </style>
</head>
<body>
  <h1>🚀 Vue 3 响应式基础训练营</h1>
  <p>在这个教程中，我们将通过创建一个简单的冒险游戏来学习Vue 3的响应式特性！</p>

  <div id="app"></div>

  <script>
    // 使用Vue 3的createApp创建应用
    const app = Vue.createApp({
      // 使用组合式API的setup函数
      setup() {
        // 导入需要的函数
        const { ref, reactive, computed, watch, onMounted, onUnmounted } = Vue

        // ============= 第一部分：使用ref创建响应式原始类型数据 =============
        console.log('🎯 第一部分：使用ref创建响应式原始类型数据')
        
        // 使用ref创建响应式数据（原始类型：数字、字符串、布尔值等）
        const heroName = ref('小勇者') // 英雄名称
        const level = ref(1)           // 等级
        const exp = ref(0)             // 经验值
        const isFighting = ref(false)  // 是否在战斗中
        
        // 示例：修改ref数据（需要使用.value）
        const gainExp = (amount) => {
          exp.value += amount
          gameLog.value.push(`获得了 ${amount} 点经验值！`)
        }

        // ============= 第二部分：使用reactive创建响应式对象 =============
        console.log('🎯 第二部分：使用reactive创建响应式对象')
        
        // 使用reactive创建响应式对象（适合复杂数据结构）
        const heroStats = reactive({
          hp: 100,        // 生命值
          mp: 50,         // 魔法值
          attack: 10,     // 攻击力
          defense: 5,     // 防御力
          skills: ['横扫千军', '火球术']
        })
        
        // 示例：修改reactive对象的属性（直接修改，不需要.value）
        const takeDamage = (damage) => {
          const actualDamage = Math.max(0, damage - heroStats.defense)
          heroStats.hp = Math.max(0, heroStats.hp - actualDamage)
          gameLog.value.push(`受到了 ${actualDamage} 点伤害！`)
          
          if (heroStats.hp === 0) {
            gameLog.value.push('⚠️ 勇者战败了！')
          }
        }

        // ============= 第三部分：使用computed创建计算属性 =============
        console.log('🎯 第三部分：使用computed创建计算属性')
        
        // 使用computed创建计算属性（根据其他响应式数据计算得出的值）
        const expToNextLevel = computed(() => {
          return level.value * 100 // 升级所需经验随等级增加
        })
        
        const isFullHealth = computed(() => {
          return heroStats.hp === 100
        })
        
        const heroStatus = computed(() => {
          if (heroStats.hp === 0) return '已战败'
          if (heroStats.hp < 30) return '重伤'
          if (heroStats.hp < 60) return '轻伤'
          return '状态良好'
        })

        // ============= 第四部分：使用watch监听数据变化 =============
        console.log('🎯 第四部分：使用watch监听数据变化')
        
        // 游戏日志
        const gameLog = ref([])
        
        // 监听经验值变化，检查是否升级
        watch(exp, (newExp, oldExp) => {
          while (newExp >= expToNextLevel.value) {
            // 升级逻辑
            newExp -= expToNextLevel.value
            level.value++
            heroStats.attack += 2
            heroStats.defense += 1
            heroStats.hp = 100
            gameLog.value.push(`🎉 恭喜！${heroName.value} 升级到了 ${level.value} 级！`)
          }
          exp.value = newExp // 更新剩余经验
        })
        
        // 监听生命值变化
        watch(() => heroStats.hp, (newHp) => {
          if (newHp === 100) {
            gameLog.value.push('✨ 生命值已满！')
          }
        })

        // ============= 第五部分：生命周期钩子 =============
        console.log('🎯 第五部分：生命周期钩子')
        
        // 定时器引用
        let battleTimer = null
        
        // 组件挂载时执行
        onMounted(() => {
          gameLog.value.push('🎮 游戏开始！欢迎来到Vue 3响应式冒险！')
        })
        
        // 组件卸载时执行（清理定时器等）
        onUnmounted(() => {
          if (battleTimer) {
            clearInterval(battleTimer)
          }
        })

        // ============= 游戏操作函数 =============
        
        // 攻击怪物
        const attackMonster = () => {
          if (isFighting.value || heroStats.hp === 0) return
          
          isFighting.value = true
          gameLog.value.push('⚔️ 开始攻击怪物！')
          
          setTimeout(() => {
            // 模拟战斗结果
            const monsterDamage = Math.floor(Math.random() * 15)
            takeDamage(monsterDamage)
            
            if (heroStats.hp > 0) {
              const expReward = Math.floor(Math.random() * 20) + 10
              gainExp(expReward)
            }
            
            isFighting.value = false
          }, 1000)
        }
        
        // 恢复生命值
        const restoreHealth = () => {
          if (heroStats.hp === 0 || isFighting.value || isFullHealth.value) return
          
          heroStats.hp = Math.min(100, heroStats.hp + 30)
          gameLog.value.push('💊 使用了治疗药水！')
        }
        
        // 更改英雄名称
        const changeHeroName = () => {
          const newName = prompt('请输入新的英雄名称：', heroName.value)
          if (newName && newName.trim()) {
            heroName.value = newName.trim()
            gameLog.value.push(`👤 英雄更名为 ${heroName.value}！`)
          }
        }
        
        // 学习新技能
        const learnNewSkill = () => {
          if (level.value < 3) {
            gameLog.value.push('📚 需要达到3级才能学习新技能！')
            return
          }
          
          const newSkills = ['闪电链', '治愈术', '隐身术', '大地之盾', '风之刃']
          const skill = newSkills[Math.floor(Math.random() * newSkills.length)]
          
          if (!heroStats.skills.includes(skill)) {
            heroStats.skills.push(skill)
            gameLog.value.push(`✨ 学会了新技能：${skill}！`)
          } else {
            gameLog.value.push('🤔 已经学会了这个技能！')
          }
        }

        // ============= 返回需要在模板中使用的数据和方法 =============
        return {
          // 响应式数据
          heroName,
          level,
          exp,
          isFighting,
          heroStats,
          
          // 计算属性
          expToNextLevel,
          isFullHealth,
          heroStatus,
          gameLog,
          
          // 方法
          attackMonster,
          restoreHealth,
          changeHeroName,
          learnNewSkill
        }
      },
      
      // 模板
      template: `
        <div>
          <!-- 游戏信息面板 -->
          <div class="section">
            <h2 class="title">🎮 Vue 3 响应式冒险游戏</h2>
            <p>这个示例展示了Vue 3组合式API的核心响应式特性！</p>
            
            <div class="code">
              <h4>🔍 学习要点：</h4>
              <ul>
                <li>✅ ref - 创建响应式原始类型数据</li>
                <li>✅ reactive - 创建响应式对象</li>
                <li>✅ computed - 计算属性</li>
                <li>✅ watch - 监听数据变化</li>
                <li>✅ 生命周期钩子</li>
              </ul>
            </div>
          </div>
          
          <!-- 英雄信息卡片 -->
          <div class="section">
            <h2 class="title">👤 英雄信息</h2>
            <div class="hero-card" :class="{ 'level-up': level % 3 === 0 }">
              <h3>名称: {{ heroName }} <button @click="changeHeroName">更改</button></h3>
              <p>等级: <span class="highlight">{{ level }}</span></p>
              <p>经验值: {{ exp }} / {{ expToNextLevel }}</p>
              <p>状态: {{ heroStatus }}</p>
              
              <h4>📊 属性</h4>
              <p>生命值: {{ heroStats.hp }}/100</p>
              <p>魔法值: {{ heroStats.mp }}/50</p>
              <p>攻击力: {{ heroStats.attack }}</p>
              <p>防御力: {{ heroStats.defense }}</p>
              
              <h4>🧙‍♂️ 技能</h4>
              <ul>
                <li v-for="skill in heroStats.skills" :key="skill">{{ skill }}</li>
              </ul>
              <button @click="learnNewSkill">学习新技能</button>
            </div>
          </div>
          
          <!-- 战斗控制 -->
          <div class="section">
            <h2 class="title">⚔️ 战斗控制</h2>
            <button @click="attackMonster" :disabled="isFighting || heroStats.hp === 0">
              {{ isFighting ? '战斗中...' : '攻击怪物' }}
            </button>
            <button @click="restoreHealth" :disabled="isFullHealth || heroStats.hp === 0 || isFighting">
              {{ isFullHealth ? '生命值已满' : '使用治疗药水' }}
            </button>
          </div>
          
          <!-- 游戏日志 -->
          <div class="section">
            <h2 class="title">📜 冒险日志</h2>
            <div class="game-log">
              <p v-for="(log, index) in gameLog" :key="index">{{ log }}</p>
            </div>
          </div>
          
          <!-- 学习指南 -->
          <div class="section">
            <h2 class="title">📖 响应式原理小知识</h2>
            <div class="code">
              <p><strong>ref vs reactive:</strong></p>
              <ul>
                <li>ref 用于原始类型数据，访问/修改需要 .value</li>
                <li>reactive 用于对象，直接访问/修改属性</li>
                <li>computed 是计算属性，会缓存结果</li>
                <li>watch 可以监听数据变化并执行副作用</li>
              </ul>
              <p>💡 提示：打开浏览器控制台，查看详细的学习步骤！</p>
            </div>
          </div>
        </div>
      `
    })
    
    // 挂载应用
    app.mount('#app')
  </script>
</body>
</html>